/* 封装工具类 */

// 封装数据类型检测的工具类
class DataType {
  // 获取数据类型
  static getType(data) {
    return Object.prototype.toString.call(data).slice(8, -1);
  }

  // 检测数据类型是否匹配
  static checkType(data, type) {
    if (!typeof type === "string") return false;
    return this.getType(data).toLowerCase() === type.toLowerCase();
  }

  // 检测数据是否为null或undefined
  static isEmpty(data) {
    if (this.checkType(data, "null")) return true;
    if (this.checkType(data, "undefined")) return true;
    // if (typeof data === "string" && data.trim() === "") return true;
    return false;
  }

  // 检测两个值是否相等（包括数组和对象）
  static isEqual(value, other) {
    if (Object.is(value, other)) return true;

    if (
      value === null ||
      other === null ||
      value === undefined ||
      other === undefined
    ) {
      return false;
    }

    if (this.getType(value) !== this.getType(other)) return false;

    // 处理数组
    if (Array.isArray(value) && Array.isArray(other)) {
      if (value.length !== other.length) return false;
      for (let i = 0; i < value.length; i++) {
        if (!isEqual(value[i], other[i])) return false;
      }
      return true;
    }

    // 处理对象（包括函数、日期等）
    if (typeof value === "object" && typeof other === "object") {
      const keysA = Object.keys(value);
      const keysB = new Set(Object.keys(other));

      if (keysA.length !== keysB.size) return false;

      for (let key of keysA) {
        if (!keysB.has(key) || !isEqual(value[key], other[key])) return false;
      }

      return true;
    }

    return false;
  }
}

// 封装数学运算的工具类
// 这里不是用proxy代理来处理round, ceil, floor。是因为这样写更直观，也更方便扩展。
class MathUtils {
  static validTypes = ["round", "ceil", "floor"];

  static roundType(number, decimals = 0, type = "round") {
    if (decimals == 0) {
      if (!this.validTypes.includes(type.toLowerCase())) {
        throw new Error("Invalid round type specified");
      }
      return Math[type](number);
    }
    const multiplier = 10 ** decimals;
    return Math[type](number * multiplier) / multiplier;
  }

  // 四舍五入、保留小数
  static round(number, decimals = 0) {
    return this.roundType(number, decimals, "round");
  }

  // 向上取整、保留小数
  static ceil(number, decimals = 0) {
    return this.roundType(number, decimals, "ceil");
  }

  // 向下取整、保留小数
  static floor(number, decimals = 0) {
    return this.roundType(number, decimals, "floor");
  }

  // 生成范围随机数
  static random(start, end) {
    return Math.floor(Math.random() * (end - start) + start);
  }

  // 取小数部分
  static decimalize(number) {
    return number - Math.trunc(number);
  }
}

// 封装字符串操作的工具类
class StrUtils {
  // 首字母大写
  static titleCase(str) {
    return str.replace(/\w\S*/g, function (txt) {
      return txt.charAt(0).toUpperCase() + txt.slice(1).toLowerCase();
    });
  }

  // 字符串插拔
  insertString(str, index, value) {
    return str.slice(0, index) + value + str.slice(index);
  }
}
// 可以直接添加到String原型链上
// String.prototype.titleCase = function () {
//   return StrUtils.titleCase(this);
// };

// 对象数组深度操作
class DeepUtils {
  // 深拷贝
  static deepCopy(obj, isNull = true) {
    if (!(obj instanceof Object)) return obj;
    let res = Array.isArray(obj) ? [] : {};
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        const value = obj[key];
        if (DataType.isEmpty(value) && !isNull) continue;
        clonedObj[key] = deepCopy(value, isNull);
      }
    }
    return res;
  }

  // 动态深度读取
  static deepGet(obj, path) {
    if (!(obj instanceof Object)) return obj;
    if (DataType.isEmpty(path)) return null;

    const pathList = path.split(".");
    let res = obj;
    for (let key of pathList) {
      if (DataType.isEmpty(res)) return null;
      res = res[key];
    }

    return res;
  }

  // 动态深度设置
  static deepSet(obj, path, value = undefined) {
    if (!(obj instanceof Object)) return obj;

    let pathList = path.split(".");
    let changePath = pathList.pop();
    let changeItem = obj;
    for (let key of pathList) {
      if (DataType.isEmpty(changeItem)) return null;
      changeItem = changeItem[key];
    }

    if (DataType.checkType(changeItem, "object")) {
      changeItem[changePath] = value;
    } else {
      throw new Error("Cannot set value to non-object");
    }

    return obj;
  }

  // 深度合并, 并控制合并出现空值时是否覆盖
  static deepMerge(value, other, isNull = false, _first = true) {
    if (!(value instanceof Object) && !(other instanceof Object) && _first) {
      throw new Error("Cannot merge non-objects");
    }

    if (value instanceof Object && other instanceof Object) {
      for (let key in other) {
        value[key] = deepMerge(value[key], other[key], isNull, false);
      }
      return value;
    }

    if (isNull) return other;
    else return DataType.isEmpty(other) ? value : other;
  }
}

// 封装字典操作的工具类
class DictUtils extends DeepUtils {
  // 迭代对象
  static Iterate(obj) {
    if (!DataType.checkType(obj, "object")) return obj;
    return {
      ...obj,
      *[Symbol.iterator]() {
        for (let key in this) {
          yield [key, this[key]];
        }
      },
    };
  }
}

// 封装列表操作的工具类
class ListUtils extends DeepUtils {}

// 封装时间操作的工具类
class TimeUtils {
  // 时间格式化
  static format(date, fmt) {
    if (!date) return "";
    if (typeof date === "string") date = new Date(date);
    const data = {
      "M+": date.getMonth() + 1, //月份
      "d+": date.getDate(), //日
      "H+": date.getHours(), //小时
      "m+": date.getMinutes(), //分
      "s+": date.getSeconds(), //秒
      "q+": Math.floor((date.getMonth() + 3) / 3), //季度
      S: date.getMilliseconds(), //毫秒
    };

    // 年
    let reg = /y+/;
    let res = reg.exec(fmt);
    if (Array.isArray(res)) {
      let y_fmt = res[0];
      fmt = fmt.replace(
        y_fmt,
        (date.getFullYear() + "").slice(4 - y_fmt.length)
      );
    }

    for (let key in data) {
      let reg = new RegExp(`(${key})`);
      let res = reg.exec(fmt);
      if (Array.isArray(res)) {
        let y_fmt = res[0];
        fmt = fmt.replace(y_fmt, (data[key] + "").padStart(y_fmt.length, "0"));
      }
    }

    return fmt;
  }
}

// 封装函数操作的工具类
class FuncUtils {
  // 函数柯里化: fn(a, b, c) => fn(a)(b)(c)
  static curry(fn) {
    return function curried(...args) {
      if (args.length >= fn.length) {
        return fn.apply(this, args);
      } else {
        return function (...nextArgs) {
          return curried.apply(this, args.concat(nextArgs));
        };
      }
    };
  }

  // 函数防抖
  static debounce(fn, delay=0) {
    let timer = null;
    return function (...args) {
      if (timer) clearTimeout(timer);
      timer = setTimeout(() => {
        fn.apply(this, args);
      }, delay);
    };
  }

  // 函数防抖-改
  static debounceImmediate(fn, delay=0) {
    let timer = null;
    return function (...args) {
      if (!timer) fn.apply(this, args);
      else clearTimeout(timer);
      timer = setTimeout(() => {
        timer = null;
      }, delay);
    };
  }

  // 函数节流
  static throttle(fn, delay) {
    let timer = null;
    return function (...args) {
      if (!timer) {
        timer = setTimeout(() => {
          fn.apply(this, args);
          timer = null;
        }, delay);
      }
    };
  }

  // 函数节流-改
  static throttleImmediate(fn, delay) {
    let timer = null;
    return function (...args) {
      if (!timer) {
        fn.apply(this, args);
        timer = setTimeout(() => {
          timer = null;
        }, delay);
      }
    };
  }
}


// 导出工具类模块
export {
  DataType,
  MathUtils,
  StrUtils,
  DictUtils,
  ListUtils,
  TimeUtils,
  FuncUtils,
};
